import _thread
import asyncio
import glob
import json
import time

import psutil
import websockets
from pyudev import Context, Monitor

context = Context()
monitor = Monitor.from_netlink(context)

# 活动的websocket链接
client = set()
command = {'显示系统信息': False, '显示USB': False}
path = glob.os.path.join(glob.os.getcwd(), 'test')  # 因为下文捕获不可读文件格式太多，所以这里直接指定了 "test04" 路径


def watch_usb():

    for device in iter(monitor.poll, None):
        if not (command['显示USB']):
            break
        if device.device_type is not None and device.device_type.find("usb", 0) != -1:
            print('{0} # {1}# {2}'.format(device.action, device.device_type, device.device_path))
            s = {
                "type": "usb-info",
                "info": str('{0} # {1}# {2}'.format(device.action, device.device_type, device.device_path))
            }
            websockets.broadcast(client, json.dumps(s))
    pass


# 单位转换
def bytes2human(n):
    symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
    prefix = {}
    for i, s in enumerate(symbols):
        prefix[s] = 1 << (i + 1) * 10
    for s in reversed(symbols):
        if n >= prefix[s]:
            value = float(n) / prefix[s]
            return '%.1f%s' % (value, s)
    return '%sB' % n


def responseMessage(code=200, message=""):
    s = {
        "code": code,
        "message": str(message)
    }
    return json.dumps(s)
    pass


# 获取系统信息
def getSystemInfo():
    while True:
        time.sleep(2)
        if not command['显示系统信息']:
            break
            pass
        # CPU占用时间
        s = {
            "type": "system-info",
            "cpu": str(psutil.cpu_percent()) + "%",
            "memery": psutil.virtual_memory()._asdict(),
        }
        websockets.broadcast(client, json.dumps(s))


def search(p, target, final_result):  # 定义 search() 函数，传入 "path" 文件路径， "target" 要查找的目标文件
    result = glob.glob(p)
    for data in result:  # for 循环判断递归查到的内容是文件夹还是文件
        # websockets.broadcast(client, responseMessage(200, "文件正在扫描:" + data))
        if glob.os.path.isdir(data):  # 若是文件夹，继续将该文件夹的路径传给 search() 函数继续递归查找
            _path = glob.os.path.join(data, '*')
            search(_path, target, final_result)
        else:  # 若是文件，则将该查询到的文件所在路径插入 final_result 空列表
            f = open(data, 'r', encoding='UTF-8')  # 利用 open() 函数读取文件，并通过 try...except... 捕获不可读的文件格式（.zip 格式）
            try:
                content = f.read()
                if target in content:
                    final_result.append(data)
            except:
                print('这是不可读文件格式的文件的所在路径：{} '.format(data))
                continue
            finally:
                f.close()

    pass


def searchMethod(p, target):
    final_result = []  # 定义一个空列表，用以存储 search() 函数查到的内容
    search(p, target, final_result)
    print('>>>>>>>>>>>文件搜索完成')
    s = {
        "type": "search-file-result",
        "path": final_result
    }
    websockets.broadcast(client, json.dumps(s))
    pass


async def handler(websocket):
    client.add(websocket)
    await  websocket.send(responseMessage(200, "欢迎登录....."))
    while True:
        try:
            message = await websocket.recv()
            s = json.loads(message)
            if not isinstance(s, dict):
                await  websocket.send(responseMessage(500, "json格式转换失败"))
                continue
                pass
            if s.get('type') == '显示系统信息':
                command['显示系统信息'] = True
                _thread.start_new_thread(getSystemInfo, ())
                pass
            if s.get('type') == '关闭系统信息':
                command['显示系统信息'] = False
                await  websocket.send(responseMessage(200, "关闭系统信息成功"))
                pass
            if s.get('type') == '查找文件':
                _thread.start_new_thread(searchMethod, (s.get('path'), s.get('content')))
                pass
            if s.get('type') == '显示USB':
                command['显示USB']=True
                _thread.start_new_thread(watch_usb, ())
                pass
            if s.get('type') == '关闭USB':
                command['显示USB'] = False
                await  websocket.send(responseMessage(200, "关闭USB成功"))
                pass
                pass

        except websockets.ConnectionClosed:
            print(">>>>>>>>>>链接关闭")
            client.remove(websocket)
            command['显示系统信息'] = False
            command['显示USB'] = False
            break
        except json.decoder.JSONDecodeError:
            await websocket.send(responseMessage(500, "json格式转换失败"))
            command['显示系统信息'] = False
            command['显示USB'] = False
            client.remove(websocket)
            break


async def main():
    async with websockets.serve(handler, "127.0.0.1", 12580):
        print('#############监控系统已经启用############')
        await asyncio.Future()  # run forever


if __name__ == "__main__":
    asyncio.run(main())
    # watch_usb()
